<?php
/**
* Copyright (c) 2002-2007 BioWare Corp.
* http://www.bigdaddymonitor.org
*
* This file is part of the BigDaddy Monitoring
* program. It is free software distributed under
* the terms of the BSD License. It is ditributed
* in the hopes that it will be useful, but
* WITHOUT ANY WARRANTY; without event the implied
* warranty of MERCHANTABILITY or FITNESS FOR A
* PARTICULAR PURPOSE.
*
* The BSD License is available from:
* http://www.opensource.org/licenses/bsd-license.php
**/
/*--------------------------------------------------------------------------------------
 WikiParseFormatting Class
 Created by Duleepa Wijayawardhana
 December 22, 2004
 
 Description: Handles the formatting of text elements in a wiki page
 This is not necessary for editors which create HTML and should not be used
 in conjunction lest errors occur

 --------------------------------------------------------------------------------------*/
class FormattingParse
{
    //Array of Wiki specific properties aligned to $this->sWikiID
    var $aWikiProperties;
    
    //Array to hold code blocks
    var $aCode;
    var $nCodeCount;
    
    //Array to hold code inline blocks
    var $aInlineCode;
    var $nInlineCodeCount;
    
    //Array to hold PHP Code blocks
    var $aPHPCode;
    var $nPHPCodeCount;
    
    //Array to hold Source Code Blocks
    var $aSourceCode;
    var $nSourceCodeCount;
	
	//Array to hold NoWiki Code Blocks
    var $aNoWikiCode;
    var $nNoWikiCount;
    
    //Variable to hold the text in question
    var $sText;
    
    //Boolean variable to turn on Debugging
    var $bIsDebug;
    var $Debug;
    
    var $bScannedOnce;
    
    //Regex string for getting style/class names in table rows etc.
    var $sCSSRegex;
    /*---------------------------------------------------------------------------------
     Constructor.
     Send in the Debug Value
     ----------------------------------------------------------------------------------*/
    function FormattingParse($sDebug = NULL)
    {
	if ($sDebug=="DEBUG")
	{
	    $this->bIsDebug=true;
	    $this->Debug = new Debug;
	}
        
	
	//Set the various counts to 0
	$this->nCodeCount=0;
	$this->nPHPCodeCount=0;
        $this->nInlineCodeCount=0;
	$this->nSourceCodeCount=0;
	$this->nNoWikiCount=0;
	$this->bScannedOnce=0;
	$this->sCSSRegex="A-Za-z0-9 \-:_%;";
    }
    /*---------------------------------------------------------------------------------
      void ParseFormatting (string sText)
      Created by Duleepa Wijayawardhana
      January 4, 2004
      
      Description: Performs the formatting parse on text supplied in sText
      ---------------------------------------------------------------------------------*/
    function ParseFormatting($sText)
    {
        $this->bScannedOnce=0;
        
	$this->sText="\n".$sText."\n";
	
	//Before we do anything else let's fix the line endings
        $this->ConvertLineEndings();
	
        //Should be done last
        $this->InLineComments();
        
	//We need to do processing of non format blocks first
        $this->NonFormatBlocksStrip();

	//Next we want to take care of line breaks
        $this->LineBreaks();
	
	//Scan the text and mark tables and lists, code sections
	$this->ScanText();
	
	//Process the tables and lists
	$this->Tables();
	$this->Lists();
	
	//Straight forward formatting
	$this->BoldItalics();
	$this->HorizontalRule();
	$this->Headings();
	$this->Strikethrough();
        
        
	
	//Put the non formatted blocks back in
        $this->NonFormatBlocksRejoin();
        
        
	
	$this->sText=trim($this->sText);
        
        return $this->sText;
    }
    /*---------------------------------------------------------------------------------
      void DebugRecord (string sType, mized mRecord, int nLine[, string sIdentity])
      Created by Duleepa Wijayawardhana
      January 4, 2004
      
      Description: Records a Debug entry into the Debug Class
      sType can be the following: "String","SQL","Array"
      mRecord information to be recorded can be string or array
      nLine the line where this was recorded from
      optional sIdentity is a string to be recorded for this entry
      ---------------------------------------------------------------------------------*/
    function DebugRecord($sType, $mRecord, $nLine, $sIdentity=NULL)
    {
	if ($this->bIsDebug==true)
	{
	    $this->Debug->DebugRecord($sType, $mRecord, $nLine, $sIdentity);
	}
    }
    /*---------------------------------------------------------------------------------
      void BoldItalics ()
      Created by Duleepa Wijayawardhana
      January 5, 2004
      
      Description: Searches for pattern '''''Text''''' to bold and italicise.
      ---------------------------------------------------------------------------------*/
    function BoldItalics()
    {
        $sTagStart="<b><i>";
	$sTagEnd="</i></b>";
	$this->sText=preg_replace("/'''''(.*?)'''''/", $sTagStart."\\1".$sTagEnd, $this->sText);
        
	$sTagStart="<b>";
	$sTagEnd="</b>";
	//For the form '''Text'''
	$this->sText=preg_replace("/'''(.*?)'''/", $sTagStart."\\1".$sTagEnd, $this->sText);
	//For the form **Text**
        //Commented out as this causes problems with lists.
	//$this->sText=preg_replace("/([\s])\*\*(.*?)\*\*([\s])/", "\\1".$sTagStart."\\2".$sTagEnd."\\3", $this->sText);
        
        $sTagStart="<i>";
	$sTagEnd="</i>";
	
	//For the form ''Text''
	$this->sText=preg_replace("/''(.*?)''/", $sTagStart."\\1".$sTagEnd, $this->sText);
    }
    /*---------------------------------------------------------------------------------
      void ConvertLineEndings ()
      Created by Duleepa Wijayawardhana
      January 5, 2004
      
      Description: Changes \r\n or \r to \n (unix line endings).
      ---------------------------------------------------------------------------------*/
    function ConvertLineEndings()
    {
	$sText=$this->sText;
	$sText=str_replace("\r\n","\n", $sText);
	$sText=str_replace("\r","\n", $sText);
	$this->sText=$sText;
    }
    /*---------------------------------------------------------------------------------
      void Headings ()
      Created by Duleepa Wijayawardhana
      January 5, 2004
      
      Description: Changes a number of equal signs to <hx> tags
      ---------------------------------------------------------------------------------*/
    function Headings()
    {
        
        for ($i=1; $i<7; $i++)
	{
    
	    $sSearchText="(=){".$i."}";
	    $sTagStart="<h".$i.">";
	    $sTagEnd="</h".$i.">";
	    $this->sText=preg_replace("/\n".$sSearchText."[ ]+(.*?)[ ]+".$sSearchText."/is", "\n".$sTagStart."\\2".$sTagEnd."\n", $this->sText);
	}
        
	/*for ($i=7; $i>0; $i--)
	{
	    $sSearchText="={".$i."}";
	    $sTagStart="<h".$i." class=\"wikiheader".$i."\">";
	    $sTagEnd="</h".$i.">";
	    $this->sText=preg_replace("/\s+".$sSearchText." (.*?) ".$sSearchText."\s+/", "\n".$sTagStart."\\1".$sTagEnd."\n", $this->sText);
	}
        */
    }
    /*---------------------------------------------------------------------------------
      void HorizontalRule ()
      Created by Duleepa Wijayawardhana
      January 5, 2004
      
      Description: Searches for pattern ---- and replaces with <hr>.
      ---------------------------------------------------------------------------------*/
    function HorizontalRule()
    {
	$sTagStart="<hr class=\"wikirule\">";
	$this->sText=preg_replace("/([\s])----/", "\\1".$sTagStart, $this->sText);
    }
    /*---------------------------------------------------------------------------------
      void HorizontalRule ()
      Created by Duleepa Wijayawardhana
      January 5, 2004
      
      Description: Searches for pattern ---- and replaces with <hr>.
      ---------------------------------------------------------------------------------*/
    function InLineComments()
    {
        $sText=$this->sText;
        //$sText=preg_replace_callback("/(``````.*?``````)/", array(&$this, 'InLineCommentProtect'), $sText);
	$sText=preg_replace_callback("/```(.*?)```/", array(&$this, 'InLineCommentProtect'), $sText);
        $this->sText=$sText;
    }
    /*---------------------------------------------------------------------------------
      void HorizontalRule ()
      Created by Duleepa Wijayawardhana
      January 5, 2004
      
      Description: Searches for pattern ---- and replaces with <hr>.
      ---------------------------------------------------------------------------------*/
    function InLineCommentProtect($aMatches)
    {
        
        $sKey="I".$this->nInlineCodeCount;
	$this->aInlineCode[$sKey]=$aMatches[1];
	$this->nInlineCodeCount++;
	return "+=CodeBlock((".$sKey."))";
    }
    
    /*---------------------------------------------------------------------------------
      void LineBreaks ()
      Created by Duleepa Wijayawardhana
      January 5, 2004
      
      Description: Place <br> tags on any line with a / at the end of
      ---------------------------------------------------------------------------------*/
    function LineBreaks()
    {
	$sText=$this->sText;
	$sText=preg_replace_callback("/\s(\/+)\n/s", array(&$this, 'LineBreakConvert'), $sText);
	$this->sText=$sText;
    }
    /*---------------------------------------------------------------------------------
      void LineBreakConvert (array aMatches)
      Created by Duleepa Wijayawardhana
      January 5, 2004
      
      Description: Called by LineBreaks()
      ---------------------------------------------------------------------------------*/
    function LineBreakConvert($aMatches)
    {
	//Number of slashes
        $nElem=strlen($aMatches[1]);
	for ($i=0; $i<$nElem; $i++)
	{
	    $sReturn.=" <br>";
	}
	//$sReturn.="\n";
	return $sReturn;
    }
    /*---------------------------------------------------------------------------------
      void Lists ()
      Created by Duleepa Wijayawardhana
      January 5, 2004
      
      Description: Calls the unordered and ordered list functions. Also rescans the text
      for lists if required.
      ---------------------------------------------------------------------------------*/
    function Lists()
    {
	$sText=$this->sText;
	$sText=preg_replace_callback("/---startstarlist---(.*?)---endstarlist---/s", array(&$this, 'ListUnorderedCheck'), $sText);
	$sText=preg_replace_callback("/---startnumberlist---(.*?)---endnumberlist---/s", array(&$this, 'ListOrderedCheck'), $sText);
	
	$this->sText=$sText;
	if (preg_match("/\n([ ]+)?\*/is", $this->sText) || preg_match("/\n([ ]+)?\#/is", $this->sText))
	{
	    $this->ScanText();
	    $this->Lists();
	}
    }
    /*---------------------------------------------------------------------------------
      void ListOrderedCheck (array aMatches)
      Created by Duleepa Wijayawardhana
      January 5, 2004
      
      Description: Creates the ordered lists
      ---------------------------------------------------------------------------------*/
    function ListOrderedCheck($aMatches)
    {
	$aLines=explode("\n", $aMatches[1]);
        
	$nCurrentLevel=1;
	for ($i=0; $i<count($aLines); $i++)
	{
	    if (preg_match("/^([ ]+)?([\#]+).*/", $aLines[$i], $aLineMatch))
	    {
		//Number of Stars
                
		$nStars=strlen($aLineMatch[2]);
		
		if ($nStars==$nCurrentLevel)
		{
		    $aLines[$i]=preg_replace("/^\s*\#+(.*)/", "<li>$1</li>", $aLines[$i]);
		}
		if ($nStars>$nCurrentLevel)
		{
		    for ($j=0; $j<($nStars-$nCurrentLevel); $j++)
		    {
			$sUL.="<ol>";
		    }
		    $aLines[$i]=preg_replace("/^\s*\#+(.*)/", $sUL."<li>$1</li>", $aLines[$i]);
		    unset($sUL);
		}
		if ($nStars<$nCurrentLevel)
		{
		    for ($j=0; $j<($nCurrentLevel-$nStars); $j++)
		    {
			$sUL.="</ol>";
		    }
		    $aLines[$i]=preg_replace("/^\s*\#+(.*)/", $sUL."<li>$1</li>", $aLines[$i]);
		    unset($sUL);
		}
		$nCurrentLevel=$nStars;
	    }
	}
	
	for ($j=0; $j<($nCurrentLevel-1); $j++)
	{
	    $sUL.="</ol>";
	}
	$aLines[]=$sUL;
	
	$sReturnStr=implode("\n", $aLines);
	$sReturnStr="<ol>".$sReturnStr."</ol>";
	return $sReturnStr;
	
    }
    /*---------------------------------------------------------------------------------
      void ListUnorderedCheck (array aMatches)
      Created by Duleepa Wijayawardhana
      January 5, 2004
      
      Description: Creates the unordered lists
      ---------------------------------------------------------------------------------*/
    function ListUnorderedCheck($aMatches)
    {
	$aLines=explode("\n", $aMatches[1]);
	
	$nCurrentLevel=1;
	for ($i=0; $i<count($aLines); $i++)
	{
	    if (preg_match("/([\*]+).*/", $aLines[$i], $aLineMatch))
	    {
		//Number of Stars
 		$nStars=strlen($aLineMatch[1]);
		if ($nStars==$nCurrentLevel)
		{
		    $aLines[$i]=preg_replace("/^\s*\*+(.*)/", "<li>$1</li>", $aLines[$i]);
		}
		if ($nStars>$nCurrentLevel)
		{
		    for ($j=0; $j<($nStars-$nCurrentLevel); $j++)
		    {
			$sUL.="<ul>";
		    }
		    $aLines[$i]=preg_replace("/^\s*\*+(.*)/", $sUL."<li>$1</li>", $aLines[$i]);
		    unset($sUL);
		}
		if ($nStars<$nCurrentLevel)
		{
		    for ($j=0; $j<($nCurrentLevel-$nStars); $j++)
		    {
			$sUL.="</ul>";
		    }
		    $aLines[$i]=preg_replace("/^\s*\*+(.*)/", $sUL."<li>$1</li>", $aLines[$i]);
		    unset($sUL);
		}
		$nCurrentLevel=$nStars;
	    }
	}
	for ($j=0; $j<($nCurrentLevel-1); $j++)
	{
	    $sUL.="</ul>";
	}
	$aLines[]=$sUL;
	unset($sUL);
	
	$sReturnStr=implode("\n", $aLines);
	$sReturnStr="<ul>".$sReturnStr."</ul>";
	return $sReturnStr;
    }
    /*---------------------------------------------------------------------------------
      void NonFormatBlocksStrip ()
      Created by Duleepa Wijayawardhana
      January 5, 2004
      
      Description: Strip out non formatting blocks so that no wiki stuff happens
      ---------------------------------------------------------------------------------*/
    function NonFormatBlocksStrip()
    {
	$sText=$this->sText;
	$sText=preg_replace_callback("/\n\<code\>(.*?)\<\/code\>/s", array(&$this, 'NonFormatCode'), $sText);
	$sText=preg_replace_callback("/\n\<phpcode\>(.*?)\<\/phpcode\>/s", array(&$this, 'NonFormatPHPCode'), $sText);
	$sText=preg_replace_callback("/\n\<sourcecode\>(.*?)\<\/sourcecode\>/s", array(&$this, 'NonFormatSourceCode'), $sText);
	$sText=preg_replace_callback("/\n\<nowiki\>(.*?)\<\/nowiki\>/s", array(&$this, 'NoWikiCode'), $sText);
	$this->sText=$sText;
    }
    /*---------------------------------------------------------------------------------
      void NonFormatCode (array aMatches)
      Created by Duleepa Wijayawardhana
      January 5, 2004
      
      Description: Strips out the <code></code> portions
      ---------------------------------------------------------------------------------*/
    function NonFormatCode($aMatches)
    {
	$sKey="C".$this->nCodeCount;
	$this->aCode[$sKey]=$aMatches[1];
	$this->nCodeCount++;
	return "\n=CodeBlock((".$sKey."))"; 
    }
    /*---------------------------------------------------------------------------------
      void NonFormatPHPCode (array aMatches)
      Created by Duleepa Wijayawardhana
      January 5, 2004
      
      Description: Strips out the <phpcode></phpcode> portions
      ---------------------------------------------------------------------------------*/
    function NonFormatPHPCode($aMatches)
    {
        $sKey="P".$this->nPHPCodeCount;
        $this->aPHPCode[$sKey]=$aMatches[1]; 
        $this->nPHPCodeCount++;
        return "\n=CodeBlock((".$sKey."))";
    }
    /*---------------------------------------------------------------------------------
      void NonFormatSourceCode (array aMatches)
      Created by Duleepa Wijayawardhana
      January 5, 2004
      
      Description: Strips out the <sourcecode></sourcecode> portions
      ---------------------------------------------------------------------------------*/
    function NonFormatSourceCode($aMatches)
    {
	$sKey="S".$this->nSourceCodeCount;
	$this->aSourceCode[$sKey]=$aMatches[1];
	$this->nSourceCodeCount++;
	return "\n=CodeBlock((".$sKey."))";
    }
	/*---------------------------------------------------------------------------------
      void NoWikiCode (array aMatches)
      Created by Duleepa Wijayawardhana
      October 14, 2005
      
      Description: Strips out the <nowiki></nowiki> portions
      ---------------------------------------------------------------------------------*/
    function NoWikiCode($aMatches)
    {
	$sKey="W".$this->nNoWikiCount;
	$this->aNoWikiCode[$sKey]=$aMatches[1];
	$this->nNoWikiCount++;
	return "\n=CodeBlock((".$sKey."))";
    }
    /*---------------------------------------------------------------------------------
      void NonFormatBlocksRejoin ()
      Created by Duleepa Wijayawardhana
      January 5, 2004
      
      Description: Re inputs code and source code blocks back into the text with the
      appropriate HTML
      ---------------------------------------------------------------------------------*/
    function NonFormatBlocksRejoin()
    {
	$sText=$this->sText;
	if (count($this->aCode)>0)
	{
	    for ($i=0; $i<$this->nCodeCount; $i++)
	    {
		$sText=str_replace("=CodeBlock((C".$i."))", "<!--CodeStart--><pre>".htmlspecialchars($this->aCode["C".$i])."</pre><!--CodeEnd-->", $sText);
	    }
	}

	if (count($this->aPHPCode)>0)
	{
	    for ($i=0; $i<$this->nPHPCodeCount; $i++)
	    {
		$sText=str_replace("=CodeBlock((P".$i."))", "<!--CodeStart--><pre>".htmlspecialchars($this->aPHPCode["P".$i])."</pre><!--CodeEnd-->", $sText);
	    }
	}
        
        if (count($this->aInlineCode)>0)
	{
	    for ($i=0; $i<$this->nInlineCodeCount; $i++)
	    {
		$sText=str_replace("+=CodeBlock((I".$i."))", "```".$this->aInlineCode["I".$i]."```", $sText);
	    }
	}
	
	if (count($this->aSourceCode)>0)
	{
	    for ($i=0; $i<$this->nSourceCodeCount; $i++)
	    {
		$sText=str_replace("=CodeBlock((S".$i."))", "<!--CodeStart--><pre>".htmlspecialchars($this->aSourceCode["S".$i])."</pre><!--CodeEnd-->", $sText);
	    }
	}
	
	if (count($this->aNoWikiCode)>0)
	{
	    for ($i=0; $i<$this->nNoWikiCount; $i++)
	    {
		$sText=str_replace("=CodeBlock((W".$i."))", "<!--CodeStart-->".$this->aNoWikiCode["W".$i]."<!--CodeEnd-->", $sText);
	    }
	}
	
	$this->sText=$sText;
    }
    
    /*---------------------------------------------------------------------------------
      void ScanText ()
      Created by Duleepa Wijayawardhana
      January 5, 2004
      
      Description: Scans the text line by line and forms paragraphs and sets start and
      end points for simple tables, ordered lists and unordered lists
      ---------------------------------------------------------------------------------*/ 
    function ScanText()
    {
	//Split the text into lines
	$sText=$this->sText;
	
	$aText=explode("\n", $sText);
	
	$this->DebugRecord("Array", $aText, __LINE__);
	$this->DebugRecord("String", $sText, __LINE__);
	
	//Add An Extra Line at the bottom
        $aText[]="";

	//Loop through the lines in the array
        $nElem=count($aText);
        for ($i=0; $i<$nElem; $i++)
	{
	    if ($bParaStarted==1 && $bDontEndPara!=1)
	    {
		$aNewText[]="</p>";
		$bParaStarted=0;
	    }
	    if ($bDontEndPara==1)
	    {
		unset($bDontEndPara);
		$bDontStartPara=1;
	    }
	    //Is there a star?
            if (preg_match("/^([ ]+)?\*/", $aText[$i]))
	    {
		//Is the list already started?
                if ($aList["started"]!=1)
		{
		    $aList["started"]=1;
		    $aList["type"]="unordered";
		    $aNewText[]="---startstarlist---";
		}
	    }
	    //Is there a number?
            elseif (preg_match("/^([ ]+)?#/", $aText[$i]))
	    {
		//Is the list already started?
                if ($aList["started"]!=1)
		{
		    $aList["started"]=1;
		    $aList["type"]="ordered";
		    $aNewText[]="---startnumberlist---";
		}
	    }
	    else if ($aList["started"]==1)
	    {
		if ($aList["type"]=="unordered")
		{
		    $aNewText[]="---endstarlist---";
		    unset($aList);
		}
		
		if ($aList["type"]=="ordered")
		{
		    $aNewText[]="---endnumberlist---";
		    unset($aList);
		}
	    }
            
            
	    //Is there a ||?
            if (preg_match("/^([ ]+)?\|\|/", $aText[$i]))
	    {
		//Is the table already started?
                if ($aTable["started"]!=1)
		{
		    $aTable["started"]=1;
		    $aNewText[]="---starttable---";
		}
	    }
	    else if ($aTable["started"]==1)
	    {
		$aNewText[]="---endtable---";
		unset($aTable);
	    }
            
            //Is there an indent command? In which case we surround this line with it. Remember it
            //has to be by line
            if (preg_match("/^(:+)/", $aText[$i], $aMatches))
            {
                $nTab=strlen($aMatches[1]);
                for ($j=0; $j<$nTab; $j++)
                {
                    $sPrefix.="<span class=\"wiki_tab\">";
                    $sAffix.="</span>";
                }
                $aText[$i]=$sPrefix.substr($aText[$i], $nTab).$sAffix;
                unset($sPrefix);
                unset($sAffix);
            }
            
	    if ($this->bScannedOnce==0)
	    {
		if (!preg_match("/^=|^\|[TRCcrt]|^\[\[/", $aText[$i])
                    && $aList["started"]!=1
                    && $aTable["started"]!=1
                    && preg_match("/\w/", $aText[$i])
                    && $bDontStartPara!=1)
		{
		    $aNewText[]="<p>";
		    $bParaStarted=1;
		    
		    if (preg_match("/<br>$/i", $aText[$i]))
		    {
			$bDontEndPara=1;
		    }
		}
                
               
	    }
            

	    unset($bDontStartPara);
	    $aNewText[]=$aText[$i];
	}
        
        
	$this->DebugRecord("Array", $aNewText, __LINE__);
	$this->sText=implode("\n", $aNewText);
	$this->bScannedOnce=1;
    }
    /*---------------------------------------------------------------------------------
      void Strikethrough ()
      Created by Duleepa Wijayawardhana
      January 4, 2004
      
      Description: Changes --Text-- To strike through
	    changed to use lookbehind/lookahead, 20060623, jesse@bioware.com.
      ---------------------------------------------------------------------------------*/
    function Strikethrough()
    {
	$sTagStart="<span style='text-decoration: line-through'>";
	$sTagEnd="</span>";
	$this->sText=preg_replace("/(?<=[\s\n])--(.*?)--(?=[\s\n<\[])/", "$sTagStart\\1$sTagEnd", $this->sText);
    }
    /*---------------------------------------------------------------------------------
      void Tables ()
      Created by Duleepa Wijayawardhana
      January 4, 2004
      
      Description: Processes $this->sText for table code
      ---------------------------------------------------------------------------------*/
    function Tables()
    {
	$sText=$this->sText;
	
	//The old (simple) table code processsing
	$sText=preg_replace_callback("/---starttable---\n(.*?)\n---endtable---/s", array(&$this, 'TablesSimple'), $sText);
	
	//Do the advanced Table stuff
        $sText=preg_replace_callback("/\n\|T(\{.*?\})?\|/s", array(&$this, 'TableAdvancedMain'), $sText);
	$sText=preg_replace_callback("/\n\|R(\{.*?\})?\|/s", array(&$this, 'TableAdvancedRow'), $sText);
	$sText=preg_replace_callback("/\n\|C(\{.*?\})?\|/s", array(&$this, 'TableAdvancedCell'), $sText);
	$sText=preg_replace("/\n\|t\|/s", "\n</table>", $sText);
	$sText=preg_replace("/\n\|r\|/s", "\n</tr>", $sText);
	$sText=preg_replace("/\n\|c\|/s", "\n</td>", $sText);

	$this->sText=$sText;
    }
    /*---------------------------------------------------------------------------------
      void TableAdvancedMain (array aMatches)
      Created by Duleepa Wijayawardhana
      January 4, 2004
      
      Description: Processes the |T| for the correct properties
      ---------------------------------------------------------------------------------*/
    function TableAdvancedMain($aMatches)
    {
	if (preg_match_all("/(Tc|Ts|W|H)\s?=\s?([".$this->sCSSRegex."]+)/", $aMatches[1], $aTMatch))
	{
	    $this->DebugRecord("Array", $aTMatch, __LINE__);
	    $nElem=count($aTMatch[1]);
	    for ($i=0; $i<$nElem; $i++)
	    {
		if ($aTMatch[1][$i]=="Tc")
		{
		    $sTableString.=" class=\"".$aTMatch[2][$i]."\"";
		}

		if ($aTMatch[1][$i]=="Ts")
		{
		    $sTableString.=" style=\"".$aTMatch[2][$i]."\"";
		}
		if ($aTMatch[1][$i]=="W")
		{
		    $sTableString.=" width=\"".$aTMatch[2][$i]."\"";
		}
		if ($aTMatch[1][$i]=="H")
		{
		    $sTableString.=" height=\"".$aTMatch[2][$i]."\"";
		}
	    }
	}
	if (preg_match_all("/(Cp|Cs|Tb)\s?=\s?([0-9]+)/", $aMatches[1], $aTMatch))
	{
	    $this->DebugRecord("Array", $aTMatch, __LINE__);
	    $nElem=count($aTMatch[1]);
	    for ($i=0; $i<$nElem; $i++)
	    {
		if ($aTMatch[1][$i]=="Tb")
		{
		    $sTableString.=" border=\"".$aTMatch[2][$i]."\"";
		}
		
		if ($aTMatch[1][$i]=="Cp")
		{
		    $sTableString.=" cellpadding=\"".$aTMatch[2][$i]."\"";
		}
		if ($aTMatch[1][$i]=="Cs")
		{
		    $sTableString.=" cellspacing=\"".$aTMatch[2][$i]."\"";
		}
	    }
	}
	$sReturn="\n<table".$sTableString.">";
	return $sReturn;
    }
    /*---------------------------------------------------------------------------------
      void TableAdvancedRow (array aMatches)
      Created by Duleepa Wijayawardhana
      January 4, 2004
      
      Description: Processes the |R| for the correct properties
      ---------------------------------------------------------------------------------*/
    function TableAdvancedRow($aMatches)
    {
	if (preg_match_all("/(Rc|Rs)\s?=\s?([".$this->sCSSRegex."]+)/", $aMatches[1], $aTMatch))
	{
	    $this->DebugRecord("Array", $aTMatch, __LINE__);
	    $nElem=count($aTMatch[1]);
	    for ($i=0; $i<$nElem; $i++)
	    {
		if ($aTMatch[1][$i]=="Rc")
		{
		    $sStr.=" class=\"".$aTMatch[2][$i]."\"";
		}

		if ($aTMatch[1][$i]=="Rs")
		{
		    $sStr.=" style=\"".$aTMatch[2][$i]."\"";
		}
	    }
	}
	$sReturn="\n<tr".$sStr.">";
	return $sReturn;
    }
    /*---------------------------------------------------------------------------------
      void TableAdvancedCell (array aMatches)
      Created by Duleepa Wijayawardhana
      January 4, 2004
      
      Description: Processes the |C| for the correct properties
      ---------------------------------------------------------------------------------*/
    function TableAdvancedCell($aMatches)
    {
	if (preg_match_all("/(Ha|Va|Vs|HS|Cc|Cs|W|H)\s?=\s?([".$this->sCSSRegex."]+)/", $aMatches[1], $aTMatch))
	{
	    $this->DebugRecord("Array", $aTMatch, __LINE__);
	    $nElem=count($aTMatch[1]);
	    for ($i=0; $i<$nElem; $i++)
	    {
		if ($aTMatch[1][$i]=="Cc")
		{
		    $sStr.=" class=\"".$aTMatch[2][$i]."\"";
		}

		if ($aTMatch[1][$i]=="Cs")
		{
		    $sStr.=" style=\"".$aTMatch[2][$i]."\"";
		}
		if ($aTMatch[1][$i]=="W")
		{
		    $sStr.=" width=\"".$aTMatch[2][$i]."\"";
		}
		if ($aTMatch[1][$i]=="H")
		{
		    $sStr.=" height=\"".$aTMatch[2][$i]."\"";
		}
		if ($aTMatch[1][$i]=="Ha")
		{
		    switch (strtolower($aTMatch[2][$i]))
		    {
			case "l":
			case "left":
			    $sStr.=" align=\"left\"";
			    break;
			case "r":
			case "right":
			    $sStr.=" align=\"right\"";
			    break;
			case "c":
			case "centre":
			case "center":
			    $sStr.=" align=\"center\"";
			    break;
		    }
		}
		if ($aTMatch[1][$i]=="Va")
		{
		    switch (strtolower($aTMatch[2][$i]))
		    {
			case "t":
			case "top":
			    $sStr.=" valign=\"top\"";
			    break;
			case "m":
			case "middle":
			case "centre":
			case "center":
			    $sStr.=" align=\"middle\"";
			    break;
			case "b":
			case "bottom":
			    $sStr.=" align=\"bottom\"";
			    break;
		    }
		}
	    }
	}
	$sReturn="\n<td".$sStr.">";
	return $sReturn;
    }
    /*---------------------------------------------------------------------------------
      void TablesSimple ()
      Created by Duleepa Wijayawardhana
      January 4, 2004
      
      Description: Takes matches from the callback to process tables
      ---------------------------------------------------------------------------------*/
    function TablesSimple($aMatches)
    {
	$aLines=explode("\n", $aMatches[1]);
	$this->DebugRecord("Array", $aLines, __LINE__);
	
	$nRows=count($aLines);
	for ($i=0; $i<$nRows; $i++)
	{
	    $sRowProperties="";
	    //If this is the first line
	    if ($i==0)
	    {
		$sTableString="";
		
		if (preg_match("/^\|\|\{(.*?)\}/", $aLines[$i], $aMatches))
		{
                    
		    //The following Table properties may be declared in the first cell
                    //Tb (borderwidth)
                    
		    if (preg_match_all("/(Tb|Tc|Ts)\s?=\s?([".$this->sCSSRegex."]+)/", $aMatches[1], $aTMatch))
		    {
                        $this->DebugRecord("Array", $aTMatch, __LINE__);
			$nElem=count($aTMatch[1]);
			for ($j=0; $j<$nElem; $j++)
			{
			    if ($aTMatch[1][$j]=="Tb" && is_numeric($aTMatch[2][$j]))
			    {
				$sTableString.=" border=\"".$aTMatch[2][$j]."\"";
			    }
			    
			    if ($aTMatch[1][$j]=="Tc")
			    {
				$sTableString.=" class=\"".$aTMatch[2][$j]."\"";
			    }
			    
			    if ($aTMatch[1][$j]=="Ts")
			    {
				$sTableString.=" style=\"".$aTMatch[2][$ij]."\"";
			    }
			}
		    }
		}
		
		if ($sTableString=="")
		{
		    $sTableString=" border=1";
		}
                    
		$aTable[]="<table".$sTableString.">";
	    }
	    
	    //Set the row properties
	    if (preg_match("/\|\|\{(.*?)\}/", $aLines[$i], $aMatches))
	    {
                $this->DebugRecord("Array", $aMatches, __LINE__);
		if (preg_match_all("/(Rc|Rs)\s?=\s?([".$this->sCSSRegex."]+)/", $aMatches[1], $aTMatch))
		{
                    
                    $nElem=count($aTMatch[1]);
		    for ($j=0; $j<$nElem; $j++)
		    {
                        if ($aTMatch[1][$j]=="Rc")
                        {
                            $sRowProperties.=" class=\"".$aTMatch[2][$j]."\"";
                        }
                        
                        if ($aTMatch[1][$j]=="Rs")
                        {
                            $sRowProperties.=" style=\"".$aTMatch[2][$j]."\"";
                        }
                    }
		}
	    }
	    
	    $aTable[]="<tr".$sRowProperties.">";
	    
	    //Now the table cells
            $nCells=substr_count($aLines[$i], "||");
            $this->DebugRecord("Array", $aLines, __LINE__);
	    $sMatch="";
	    for ($j=0; $j<$nCells-1; $j++)
	    {
		$sMatch.="(.*?)\|\|";
	    }
	    $sMatch="/\|\|".$sMatch."/";
	    $this->DebugRecord("String", $sMatch, __LINE__);
	    
            preg_match($sMatch, $aLines[$i], $aMatches);
	    $this->DebugRecord("Array", $aMatches, __LINE__);
	    
	    //How many cells in this row?
            $nCells=count($aMatches);
	    for ($j=1; $j<$nCells; $j++)
	    {
		preg_match("/(\{.*?\})?(.*)/", $aMatches[$j], $aCellMatches);
		$sCellBegin="";
		$sCellEnd="";
		$sCellProperties="";
		
		//Get any table properties
		if (preg_match("/\bl\b/", $aCellMatches[1]))
		{
		    $sCellProperties.=" align=\"left\"";
		}
		elseif (preg_match("/\bc\b/", $aCellMatches[1]))
		{
		    $sCellProperties.=" align=\"center\"";
		}
		elseif (preg_match("/\br\b/", $aCellMatches[1]))
		{
		    $sCellProperties.=" align=\"right\"";
		}
		
		
		if (preg_match("/\bt\b/", $aCellMatches[1]))
		{
		    $sCellProperties.=" valign=\"top\"";
		}
		elseif (preg_match("/\bm\b/", $aCellMatches[1]))
		{
		    $sCellProperties.=" valign=\"middle\"";
		}
		elseif (preg_match("/\bb\b/", $aCellMatches[1]))
		{
		    $sCellProperties.=" valign=\"bottom\"";
		}
		
		if (preg_match("/h\s?=\s?([0-9]+)/", $aCellMatches[1], $aRowSpanMatch))
		{
		    $sCellProperties.=" rowspan=\"".$aRowSpanMatch[1]."\"";
		}
		
		if (preg_match("/w\s?=\s?([0-9]+)/", $aCellMatches[1], $aColsSpanMatch))
		{
		    $sCellProperties.=" colspan=\"".$aColsSpanMatch[1]."\"";
		}
		if (preg_match("/C\s?=\s?([".$this->sCSSRegex."]+)\b/", $aCellMatches[1], $aClassMatch))
		{
		    $sCellProperties.=" class=\"".$aClassMatch[1]."\"";
		}
		if (preg_match("/\bs\s?=\s?([".$this->sCSSRegex."]+)\b/", $aCellMatches[1], $aStyleMatch))
		{
		    $sCellProperties.=" style=\"".$aStyleMatch[1]."\"";
		}
		$aTable[]="<td".$sCellProperties.">";
                if (preg_match("/\bB\b/", $aCellMatches[1]))
		{
		    $sCellBegin.="<b>";
		    $sCellEnd.="</b>";
		}
		if (preg_match("/\bI\b/", $aCellMatches[1]))
		{
		    $sCellBegin.="<i>";
		    $sCellEnd="</i>".$sCellEnd;
		}
		if (preg_match("/\bU\b/", $aCellMatches[1]))
		{
		    $sCellBegin.="<u>";
		    $sCellEnd="</u>".$sCellEnd;
		}
		$aTable[]=$sCellBegin.$aCellMatches[2].$sCellEnd."</td>";
		
	    }
	    
	    $aTable[]="</tr>";
	}
	$aTable[]="</table>";
	$this->DebugRecord("Array", $aTable, __LINE__);
	$sReturnStr=implode("\n", $aTable);
	return $sReturnStr;
    }
}



?>
